<?php
/**
 * Parcl
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://parcl.com/license
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@parcl.com so we can send you a copy immediately.
 *
 * @category parcl
 * @package parcl-core
 * @copyright Copyright (c) 2006-2011 Mikael Knutsson (http://mikn.me)
 * @license http://parcl.com/license New BSD License
 * 
 * @author mikael
 */

namespace Parcl\Core {

	if(PARCL_EXEC !== 1) {
		die('<h1>Incorrect Access</h1>You cannot access this file directly.<br/>' .
			 'If you got this error message by clicking a link on the site,' .
			 'please notify the webmaster as soon as possible.');
	}

	/**
	 * Purpose     : The container for an EventHandler, when an event is raised, it
					 executes the contained callback.
	 * Description : It contains everything an EventHandler is supposed to.
	 * - Construct -
	 * Input       : $event: An Event.
					 $callback: The callback to be triggered when the specific event
					 is triggered.
	 * Output      : Not applicable.
	 * Description : It adds the Event to the class variable and prepares the callback
					 for execution.
	 * Errors      : Throws an error if $event isn't an Event or if you try to add
					 a callback to an already triggered event.
	 * Assumptions : That $callback is either a string or an array.
	 * Dev Notes   : None at the moment.
	 */

	class EventHandler {
		private $event;
		private $callback;

		public function __construct($event, $callback) {
			Event::IsEvent($event);
			$this->event = $event;
			$events = EventCollection::GetInstance();
			if(in_array($event, $events->GetFlagTriggered())) {
				throw new EventException('Tried to add ' . print_r($callback, true) . ' callback to ' .
										 'an already triggered event.', EventException::EVENT);
			}
			$this->callback = $this->prepareCallback($callback);
		}

		/**
		 * Input       : None.
		 * Output      : The name of the event of this specific EventHandler.
		 * Description : Returns the name of the event of the specific EventHandler..
		 * Errors      : None.
		 * Assumptions : That __construct has ben run and assigned the class variable $event.
		 * Dev Notes   : Calls on the same function in the Event class.
		 */

		public function GetEventName() {
			return $this->event->GetName();
		}

		/**
		 * Input       : $sender: The $this variable of the sender class.
						 $args: An array of the rest of the arguments passed to the callback.
		 * Output      : No real output.
		 * Description : This function calls on the callback specified in the EventHandler
						 when the event is triggered, it passes all the necessary arguments
						 with $sender first.
		 * Errors      : Trows an error if the callback specified isn't callable.
		 * Assumptions : That $args is an array, and that $sender is the class
						 instance of the sender.
		 * Dev Notes   : Need to get rid of the assumptions.
		 */

		public function Raise($sender, $args) {
			if(!is_callable($this->callback)) {
				throw new EventException('Tried to raise an event without callback'
										  . ' or used an invalid event handler.'
										  . ' Callback: ' . print_r($this->callback, true),
										  EventException::CALLBACK);
			}
			/***
			 * Make $sender the first variable in the argument list since we might
			 * want to call functions that doesn't require any more variables than that.
			 */
			call_user_func($this->callback, $sender, $args);
		}

		/**
		 * Input       : $callbck: The callback to prepare.
		 * Output      : $callbck: The prepared callback.
		 * Description : Checks if it is an array or not, prepares it if necessary
						 (meaning we cut off the parenthesis if someone put it there).
		 * Errors      : No error conditions have been defined.
		 * Assumptions : That $callbck is is a string if it isn't an array.
		 * Dev Notes   : Pretty neat function.
		 */

		private function prepareCallback($callbck) {
			(is_array($callbck) ? $callback = &$callbck[1] : $callback = &$callbck);
			if($pos = strpos($callback, '(')) {
				$callback = substr($callback, 0, $pos);
			}
			return $callbck;
		}

		/**
		 * Input       : $handler: Any variable.
		 * Output      : Boolean true if it is an EventHandler.
		 * Description : This function checks if $handler is an EventHandler or not.
		 * Errors      : Throws an error if $handler isn't an EventHandler.
		 * Assumptions : None.
		 * Dev Notes   : Created for the same reason as IsEvent();
		 */

		public static function IsEventHandler($handler) {
			if(!$handler instanceof EventHandler) {
				throw new EventException('Tried to add an invalid event handler.',
										  EventException::HANDLER);
			}
			return true;
		}

	}
}